package com.groupten.ServiceImpl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.groupten.Dao.PaperDao;
import com.groupten.Entity.ConfigureRuleEntity;
import com.groupten.Entity.PaperEntity;
import com.groupten.Entity.QuestionEntity;
import com.groupten.Service.*;
import com.groupten.Entity.WqHouseEntity;
import com.groupten.Vo.ExamVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.awt.print.Paper;
import java.time.LocalDateTime;
import java.util.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.List;

@Service("paperService")
public class PaperServiceImpl extends ServiceImpl<PaperDao, PaperEntity> implements PaperService {
    List<QuestionEntity> WAlist=new ArrayList<QuestionEntity>();

    @Autowired
    private DictDataService dictDataService;
    @Autowired
    private ConfigureRuleService configureRuleService;
    @Autowired
    private QuestionService questionService;
    @Autowired
    private WqHouseService wqHouseService;
    private PaperService paperService;

    @Override
    public Integer insertPaper(PaperEntity paperEntity) {
        return baseMapper.insert(paperEntity);
    }

    @Override
    public Integer deletePaperById(Long Id) {
        LambdaQueryWrapper<PaperEntity> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.eq(ObjectUtils.isNotEmpty(Id),PaperEntity::getPaperId,Id);

        return baseMapper.delete(queryWrapper);
    }

    @Override
    public Integer deleteBySession(Integer sessionId) {
        LambdaQueryWrapper<PaperEntity> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.eq(ObjectUtils.isNotEmpty(sessionId),PaperEntity::getPaperSession,sessionId);

        return baseMapper.delete(queryWrapper);
    }

    @Override
    public IPage<PaperEntity> selectAll(Integer page, Integer limit) {
        int curPage = 1;
        int curLimit = 10;
        if (ObjectUtils.isNotEmpty(page)) {
            curPage = Integer.parseInt(page.toString());
        }
        if (ObjectUtils.isNotEmpty(limit)) {
            curLimit = Integer.parseInt(limit.toString());
        }

        IPage<PaperEntity> pageObject = Page.of(curPage, curLimit);

        return baseMapper.selectPage(pageObject, Wrappers.lambdaQuery());
    }

    @Override
    public IPage<PaperEntity> selectBySubject(Integer Subject, Integer page, Integer limit) {
        LambdaQueryWrapper<PaperEntity> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.eq(ObjectUtils.isNotEmpty(Subject),PaperEntity::getPaperSubject,Subject);

        int curPage = 1;
        int curLimit = 10;
        if (ObjectUtils.isNotEmpty(page)) {
            curPage = Integer.parseInt(page.toString());
        }
        if (ObjectUtils.isNotEmpty(limit)) {
            curLimit = Integer.parseInt(limit.toString());
        }

        IPage<PaperEntity> pageObject = Page.of(curPage, curLimit);

        return baseMapper.selectPage(pageObject, queryWrapper);
    }

    @Override
    public IPage<PaperEntity> selectBySession(Integer Session, Integer page, Integer limit) {
        LambdaQueryWrapper<PaperEntity> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.eq(ObjectUtils.isNotEmpty(Session),PaperEntity::getPaperSession,Session);

        int curPage = 1;
        int curLimit = 10;
        if (ObjectUtils.isNotEmpty(page)) {
            curPage = Integer.parseInt(page.toString());
        }
        if (ObjectUtils.isNotEmpty(limit)) {
            curLimit = Integer.parseInt(limit.toString());
        }

        IPage<PaperEntity> pageObject = Page.of(curPage, curLimit);

        return baseMapper.selectPage(pageObject, queryWrapper);
    }

    @Override
    public IPage<PaperEntity> selectByQuestionId(Integer QuestionId, Integer page, Integer limit) {
        LambdaQueryWrapper<PaperEntity> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.eq(ObjectUtils.isNotEmpty(QuestionId),PaperEntity::getQuestionId,QuestionId);

        int curPage = 1;
        int curLimit = 10;
        if (ObjectUtils.isNotEmpty(page)) {
            curPage = Integer.parseInt(page.toString());
        }
        if (ObjectUtils.isNotEmpty(limit)) {
            curLimit = Integer.parseInt(limit.toString());
        }

        IPage<PaperEntity> pageObject = Page.of(curPage, curLimit);

        return baseMapper.selectPage(pageObject, queryWrapper);
    }

    /**
     *
     * @param answerSheet 题号与作答字典列表
     * @return Map格式考试结果，(得分:错题列表)
     */
    @Override
    public Map<Double,List<QuestionEntity> > scoring(Map<Integer, String>  answerSheet) {
        double score = 0.0;
        for(Map.Entry<Integer,String> entry:answerSheet.entrySet()) {
            Long answerId = entry.getKey().longValue();//获得题目编号
            String answer = entry.getValue();//获得作答内容
            QuestionEntity qe = questionService.selectQuestionByID(answerId);
            if(qe != null && answer.equals(qe.getAnswerText())) {
                score = score + qe.getScore();//获得答案，并判分
            }
            else{
                WAlist.add(qe);
            }
        }
        Map<Double,List<QuestionEntity> > map = new HashMap<>();
        map.put(score,WAlist);
        return map;
    }

    @Override
    public IPage<QuestionEntity> generatePaperByRule(String subject, Integer session, ConfigureRuleEntity rule, Integer page, Integer limit, LocalDateTime now) {
        //获取学科，单选题，多选题，填空题对应的int值
        Integer subjectvalue = dictDataService.queryByLabel(subject).getDictValue();
        Integer singlevalue = dictDataService.queryByLabel("单选题").getDictValue();
        Integer multiplevalue = dictDataService.queryByLabel("多选题").getDictValue();
        Integer blankvalue=dictDataService.queryByLabel("填空题").getDictValue();
        //根据规则试卷需要的单选题个数、多选题个数、填空题个数和通过率
        if (rule==null){   //如果不传递规则，则采用默认规则    
            rule=configureRuleService.selectById(1L);
        }
        Integer singlechoiceNumber = rule.getSinglechoiceNumber();
        Integer multiplechoiceNumber = rule.getMultiplechoiceNumber();
        Integer blankNumber = rule.getBlankNumber();
        Double passingRate = rule.getPassingRate();
        //根据学科和题目类型从题库中获取题目，存到对应的题目列表里
        List<QuestionEntity> singlechoicequestions=null;
        List<QuestionEntity> multiplechoicequestions=null;
        List<QuestionEntity> blankquestions=null;
        if (singlechoiceNumber!=null && singlechoiceNumber>0){
            //说明现在试卷需要单选题
            singlechoicequestions = questionService.selectQuestionBySubjectAndType(subjectvalue, singlevalue, null, 300).getRecords();
        }
        if (multiplechoiceNumber!=null && multiplechoiceNumber>0){
            //说明现在试卷需要多选题
            multiplechoicequestions = questionService.selectQuestionBySubjectAndType(subjectvalue, multiplevalue, null, 300).getRecords();
        }
        if (blankNumber!=null && blankNumber>0){
            blankquestions = questionService.selectQuestionBySubjectAndType(subjectvalue, blankvalue, null, 300).getRecords();
        }
        //创建试卷题目集合，默认为空，将满足条件的题目添加到这里面
        Random random = new Random();
        ArrayList<QuestionEntity> paperquestions = new ArrayList<QuestionEntity>();
        //循环添加单选题，如果剩余所需单选题数量大于0，则继续添加
        addQuestionsToPaper(singlechoiceNumber, passingRate, singlechoicequestions, random, paperquestions);
        addQuestionsToPaper(multiplechoiceNumber, passingRate, multiplechoicequestions, random, paperquestions);
        addQuestionsToPaper(blankNumber, passingRate, blankquestions, random, paperquestions);
        //此时试卷题目集合paperquestions中包含了所有满足条件的题目，可以开始生成试卷
        LocalDateTime currentNow = now;
        if (currentNow == null) {
            currentNow = LocalDateTime.now();
        }
        addIntoPaperTable(paperquestions, subjectvalue, session, currentNow);
        //设置分页参数
        int curPage = 1;
        int curLimit = 10;
        if (page!=null && page>0) {
            curPage = page;
        }
        if (limit!=null && limit>0) {
            curLimit = limit;
        }
        return questionService.convertListtoIPage(paperquestions, curPage, curLimit);
    }

    @Override
    public IPage<QuestionEntity> generatePaperByKnowledgePoint(String[] knowledgePoints, Integer session, ConfigureRuleEntity rule, Integer page, Integer limit, LocalDateTime now) {
        //拿到所有知识点对应的值
        Integer[] knowledgePointsValue = new Integer[knowledgePoints.length];
        for (int i = 0; i < knowledgePoints.length; i++) {
            knowledgePointsValue[i] = dictDataService.queryByLabel(knowledgePoints[i]).getDictValue();
        }
        return generatePaperByKnowledgePoint(knowledgePointsValue, session, rule, page, limit, now);
    }

    @Override
    public IPage<QuestionEntity> generatePaperByKnowledgePoint(Integer[] knowledgePointsValue, Integer session, ConfigureRuleEntity rule, Integer page, Integer limit, LocalDateTime now) {
        ArrayList<QuestionEntity> paperquestions = generatePaperQuestionsListByKnowledgePoints(knowledgePointsValue, rule);
        //此时试卷题目集合paperquestions中包含了所有满足条件的题目，可以开始生成试卷
        LocalDateTime currentNow = now;
        if (currentNow == null) {
            currentNow = LocalDateTime.now();
        }
        Integer subjectvalue = knowledgePointsValue[0]/100; //根据知识点获取题目对应的科目
        addIntoPaperTable(paperquestions, subjectvalue, session, currentNow);
        //设置分页参数
        int curPage = 1;
        int curLimit = 10;
        if (page!=null && page>0) {
            curPage = page;
        }
        if (limit!=null && limit>0) {
            curLimit = limit;
        }
        return questionService.convertListtoIPage(paperquestions, curPage, curLimit);
    }

    private ArrayList<QuestionEntity> generatePaperQuestionsListByKnowledgePoints(Integer[] knowledgePointsValue, ConfigureRuleEntity rule) {
        //获取单选题，多选题，填空题对应的int值
        Integer singlevalue = dictDataService.queryByLabel("单选题").getDictValue();
        Integer multiplevalue = dictDataService.queryByLabel("多选题").getDictValue();
        Integer blankvalue=dictDataService.queryByLabel("填空题").getDictValue();
        //根据规则获得每个知识点需要的单选题个数、多选题个数、填空题个数和通过率
        if (rule ==null){   //如果不传递规则，则采用默认规则
            rule =configureRuleService.selectById(1L);
        }
        Integer singlechoiceNumber = rule.getSinglechoiceNumber();
        Integer multiplechoiceNumber = rule.getMultiplechoiceNumber();
        Integer blankNumber = rule.getBlankNumber();
        Double passingRate = rule.getPassingRate();
        //创建试卷题目集合，默认为空，将满足条件的题目添加到这里面
        ArrayList<QuestionEntity> paperquestions = new ArrayList<QuestionEntity>();
        //根据知识点和题目类型从题库中获取题目，存到对应的题目列表里
        List<QuestionEntity> singlechoicequestions=new ArrayList<>();
        List<QuestionEntity> multiplechoicequestions=new ArrayList<>();
        List<QuestionEntity> blankquestions=new ArrayList<>();
        Random random = new Random();
        if (singlechoiceNumber!=null && singlechoiceNumber>0){
            //说明现在试卷需要单选题，把所有满足知识点和题目类型的题目加入集合中
            for (Integer knowledgePoint : knowledgePointsValue){
                singlechoicequestions.addAll(questionService.selectQuestionByKnowledgePointAndType(knowledgePoint, singlevalue, null, 300).getRecords());
                //当前singlechoicequesitons中包含了满足当前知识点和题目类型的300条题目
                addQuestionsToPaper(singlechoiceNumber, passingRate, singlechoicequestions, random, paperquestions);
                singlechoicequestions.clear();
            }
        }
        if (multiplechoiceNumber!=null && multiplechoiceNumber>0){
            //说明现在试卷需要多选题
            for (Integer knowledgePoint : knowledgePointsValue){
                multiplechoicequestions.addAll(questionService.selectQuestionByKnowledgePointAndType(knowledgePoint, multiplevalue, null, 300).getRecords());
                addQuestionsToPaper(multiplechoiceNumber, passingRate, multiplechoicequestions, random, paperquestions);
                multiplechoicequestions.clear();
            }
        }
        if (blankNumber!=null && blankNumber>0){
            for (Integer knowledgePoint : knowledgePointsValue){
                blankquestions.addAll(questionService.selectQuestionByKnowledgePointAndType(knowledgePoint, blankvalue, null, 300).getRecords());
                addQuestionsToPaper(blankNumber, passingRate, blankquestions, random, paperquestions);
                blankquestions.clear();
            }
        }
        return paperquestions;
    }

    @Override
    public IPage<QuestionEntity> generatePaperByWq(String stuNumber, String subject, Integer session, ConfigureRuleEntity rule, Integer page, Integer limit, LocalDateTime now) {
        //设置分页参数
        int curPage = 1;
        int curLimit = 10;
        if (page!=null && page>0) {
            curPage = page;
        }
        if (limit!=null && limit>0) {
            curLimit = limit;
        }
        //创建试卷题目集合，默认为空，将满足条件的题目添加到这里面
        ArrayList<QuestionEntity> paperquestions = new ArrayList<QuestionEntity>();
        //获取学科对应的value值
        Integer subjectvalue = dictDataService.queryByLabel(subject).getDictValue();
        //获取该学生指定科目的所有错题
        List<WqHouseEntity> wqList = wqHouseService.selectWqHouseListByStudentNumberAndSubject(stuNumber, subjectvalue);
        if (wqList.isEmpty()){
            //没有错题，不生成试卷，直接返回空试卷
            return questionService.convertListtoIPage(paperquestions, curPage, curLimit);
        }
        //统计这些错题涉及的所有知识点，以及平均难度
        HashMap<Integer, Double> knowledgePointAndLevel = new HashMap<>(); //保存出现的所有的知识点，以及难度和
        HashMap<Integer, Integer> knowledgePointAndNumber = new HashMap<>(); //保存出现的所有知识点，及其出现次数
        for (WqHouseEntity wq : wqList){
            if (knowledgePointAndLevel.containsKey(wq.getKnowledgePoint())){
                knowledgePointAndLevel.put(wq.getKnowledgePoint(), knowledgePointAndLevel.get(wq.getKnowledgePoint())+wq.getLevel());
                knowledgePointAndNumber.put(wq.getKnowledgePoint(), knowledgePointAndNumber.get(wq.getKnowledgePoint())+1);
            }else {
                knowledgePointAndLevel.put(wq.getKnowledgePoint(), wq.getLevel());
                knowledgePointAndNumber.put(wq.getKnowledgePoint(), 1);
            }
        }
        for (Integer knowledgePoint : knowledgePointAndLevel.keySet()){
            knowledgePointAndLevel.put(knowledgePoint, knowledgePointAndLevel.get(knowledgePoint)/knowledgePointAndNumber.get(knowledgePoint));
        }
        //如果没有传递规则，则采用默认规则，但难度根据每个知识点进行设置
        if (rule==null){
            rule = configureRuleService.selectById(1L);
        }
        //此时knowledgePointAndLevel中包含了所有知识点及其平均难度
        for (Integer knowledgePoint : knowledgePointAndLevel.keySet()){
            //先按照每个知识点的平均难度设置规则的难度，根据知识点得到题目集合
            rule.setPassingRate(knowledgePointAndLevel.get(knowledgePoint));
            paperquestions.addAll(generatePaperQuestionsListByKnowledgePoints(new Integer[]{knowledgePoint}, rule));
        }
        //此时将所有题目添加到试卷中
        LocalDateTime currentNow = now;
        if (currentNow == null) {
            currentNow = LocalDateTime.now();
        }
        addIntoPaperTable(paperquestions, subjectvalue, session, currentNow);
        return questionService.convertListtoIPage(paperquestions, curPage, curLimit);
    }

    @Override
    public void deleteObsoleteQuestion() {
        List<PaperEntity> allPapers = baseMapper.selectList(Wrappers.lambdaQuery());
        for (PaperEntity paper : allPapers){
            if (questionService.selectQuestionByID(paper.getQuestionId())==null){
                baseMapper.deleteById(paper.getPaperId());
            }
        }
    }



    private void addIntoPaperTable(List<QuestionEntity> paperquestions, Integer subjectvalue, Integer session, LocalDateTime now){
        for (QuestionEntity paperquestion : paperquestions){
            PaperEntity paperEntity = new PaperEntity();
            paperEntity.setPaperSubject(subjectvalue);
            paperEntity.setQuestionId(paperquestion.getQuestionId());
            paperEntity.setPaperSession(session);
            paperEntity.setPaperTime(now);
            insertPaper(paperEntity);
        }
    }

    private void addQuestionsToPaper(Integer questionNumberNeed, Double passingRate, List<QuestionEntity> questionsList, Random random, ArrayList<QuestionEntity> paperQuestions) {
        Integer questionNumber = questionNumberNeed;
        Integer hardNumberNeed = (int) (questionNumberNeed * 0.2);
        Integer hardNumberAdded = 0;
        Integer easyNumberNeed = 0;
        Integer easyNumberAdded = 0;
        ArrayList<QuestionEntity> hardQuestionsList = new ArrayList<QuestionEntity>();
        ArrayList<QuestionEntity> easyQuestionsList = new ArrayList<QuestionEntity>();
        ArrayList<QuestionEntity> middleQuestionsList = new ArrayList<QuestionEntity>();
        if (questionsList != null && !questionsList.isEmpty()){
            for (QuestionEntity question : questionsList){
                if (question.getLevel()<passingRate-0.1 && question.getLevel()>=passingRate-0.25){
                    hardQuestionsList.add(question);
                }else if (question.getLevel()>passingRate+0.1 && question.getLevel()<=passingRate+0.25){
                    easyQuestionsList.add(question);
                }else if (question.getLevel()>=passingRate-0.1 && question.getLevel()<=passingRate+0.1){
                    middleQuestionsList.add(question);
                }
            }
        }
        while (hardQuestionsList != null && !hardQuestionsList.isEmpty() && hardNumberNeed!=0){
            int index = random.nextInt(hardQuestionsList.size());
            paperQuestions.add(hardQuestionsList.get(index));
            hardQuestionsList.remove(index);
            hardNumberNeed--;
            hardNumberAdded++;
        }
        easyNumberNeed = hardNumberAdded;
        while (easyQuestionsList != null && !easyQuestionsList.isEmpty() && easyNumberNeed!=0){
            int index = random.nextInt(easyQuestionsList.size());
            paperQuestions.add(easyQuestionsList.get(index));
            easyQuestionsList.remove(index);
            easyNumberNeed--;
            easyNumberAdded++;
        }
        questionNumber = questionNumber - hardNumberAdded - easyNumberAdded;
        while (middleQuestionsList != null && !middleQuestionsList.isEmpty() && questionNumber!=0){
            int index = random.nextInt(middleQuestionsList.size());
            paperQuestions.add(middleQuestionsList.get(index));
            middleQuestionsList.remove(index);
            questionNumber--;
        }
    }

    @Override
    public void questionDisplay(IPage<PaperEntity> paperEntity) {
        List<PaperEntity> paperEntityList = paperEntity.getRecords();
        QuestionEntity questionEntity = new QuestionEntity();
        int i=1;
        for(PaperEntity usingQuestion: paperEntityList){
            questionEntity=questionService.selectQuestionByID(usingQuestion.getQuestionId());
            String string=new String();
            string=String.valueOf(i);
            System.out.print(string+".");
            i++;
            System.out.print(questionEntity.getQuestionId());
            System.out.println(questionEntity.getQuestionText());
            System.out.println();
        }
    }

    @Override
    public ExamVo answerSheetGenerate(Integer paperSession, IPage<PaperEntity> paperEntity) {
        ExamVo answerSheet = new ExamVo();
        answerSheet.setPaperSession(paperSession);   //获得答题卡对应考试场次

        Map<Integer, String> answerSheetBody = new HashMap<>(); //生成答题卡题目编号
        List<PaperEntity> paperEntityList = paperEntity.getRecords();
        for(PaperEntity usingQuestion: paperEntityList){
            QuestionEntity questionEntity; //获得试卷中的题目

            questionEntity=questionService.selectQuestionByID(usingQuestion.getQuestionId()); //获得题目id，将题目id设定为答题卡的Key，初始化答案为空串
            Long i=questionEntity.getQuestionId();
            answerSheetBody.put(Integer.valueOf(String.valueOf(i)),"");
        }
        answerSheet.setAnswer(answerSheetBody); //答案区录入答题卡
        return answerSheet; //返回一张空答题卡用于作答
    }
    @Override
    public Map<Integer,String> answerSet(ExamVo answerSheet){
        Map<Integer, String> answers=answerSheet.getAnswer();
        int i=1;
        for(Integer key:answers.keySet()){
            System.out.print(i+".");
            Scanner scanner=new Scanner(System.in);
            answers.put(key,scanner.nextLine()); //将输入的答案录入答题卡对应区域，允许留空
            i++;
        }
        return answers;
    }


}
